package metrics

import (
	"context"
	"git.multiverse.io/eventkit/common/model/mgmt"
	"git.multiverse.io/eventkit/common/util"
	"git.multiverse.io/eventkit/dxc-server/client"
	"git.multiverse.io/eventkit/dxc-server/config"
	"git.multiverse.io/eventkit/kit/client/mesh"
	"git.multiverse.io/eventkit/kit/codec"
	codec_text "git.multiverse.io/eventkit/kit/codec/text"
	"git.multiverse.io/framework/log"
	jsoniter "github.com/json-iterator/go"
	"time"
)

var (
	json = jsoniter.ConfigCompatibleWithStandardLibrary
)

type MetricsReporter struct{}

func currentMetrics() mgmt.Metrics {
	metrics := mgmt.Metrics{
		TxnBegin: mgmt.MetricInfo{
			TPS:         DTSRegisterTPSAnalyser.GetTPSOfIntervalCountingTimeAndReset(),
			AvgTimeCost: DTSRegisterTimeCostAvgAnalyser.GetAvgOfIntervalCountingTimeAndReset(),
			SuccessRate: DTSRegisterSuccessRateAnalyser.GetSuccessRateOfIntervalCountingTimeAndReset(),
		},
		TxnJoin: mgmt.MetricInfo{
			TPS:         DTSEnlistTPSAnalyser.GetTPSOfIntervalCountingTimeAndReset(),
			AvgTimeCost: DTSEnlistTimeCostAvgAnalyser.GetAvgOfIntervalCountingTimeAndReset(),
			SuccessRate: DTSEnlistSuccessRateAnalyser.GetSuccessRateOfIntervalCountingTimeAndReset(),
		},
		TxnEnd: mgmt.MetricInfo{
			TPS:         DTSTryResultReportTPSAnalyser.GetTPSOfIntervalCountingTimeAndReset(),
			AvgTimeCost: DTSTryResultReportTimeCostAvgAnalyser.GetAvgOfIntervalCountingTimeAndReset(),
			SuccessRate: DTSTryResultReportSuccessRateAnalyser.GetSuccessRateOfIntervalCountingTimeAndReset(),
		},
		CallbackConfirm: mgmt.MetricInfo{
			TPS:         DTSCallbackConfirmTPSAnalyser.GetTPSOfIntervalCountingTimeAndReset(),
			AvgTimeCost: DTSCallbackConfirmTimeCostAvgAnalyser.GetAvgOfIntervalCountingTimeAndReset(),
			SuccessRate: DTSCallbackConfirmSuccessRateAnalyser.GetSuccessRateOfIntervalCountingTimeAndReset(),
		},
		CallbackCancel: mgmt.MetricInfo{
			TPS:         DTSCallbackCancelTPSAnalyser.GetTPSOfIntervalCountingTimeAndReset(),
			AvgTimeCost: DTSCallbackCancelTimeCostAvgAnalyser.GetAvgOfIntervalCountingTimeAndReset(),
			SuccessRate: DTSCallbackCancelSuccessRateAnalyser.GetSuccessRateOfIntervalCountingTimeAndReset(),
		},
		MetricsTime: util.CurrentTime(),
	}

	return metrics
}

func StartDTSMetricsReport() error {
	if !config.Cfg.Metrics.Enable {
		log.Infosf("Metrics has disabled, skip metrics report!")
		return nil
	}
	// gather all current metrics and then report to the DTS management Agent
	go func() {
		ticker := time.NewTicker(time.Second * time.Duration(config.Cfg.Metrics.ReportIntervalSeconds))
		for {
			select {
			case <-ticker.C:
				// gather all current metrics and report to the DTS management Agent
				doMetricsRequest := mgmt.DoMetricsRequest{}
				doMetricsRequest.Metrics = []mgmt.Metrics{currentMetrics()}
				doMetricsRequest.RequestTime = util.CurrentTime()

				// marshal request byte array
				reqBody, err := json.Marshal(doMetricsRequest)
				if nil != err {
					log.Errorsf("Marshal request body failed, error=%++v", err)
					continue
				}
				request := mesh.NewMeshRequest(reqBody)
				request.WithOptions(
					mesh.WithTopicTypeOps(),
					mesh.WithEventID(config.Cfg.Metrics.ReportToTopicID),
					mesh.WithMaxRetryTimes(1),
					mesh.WithTimeout(time.Duration(30000)*time.Millisecond),
					mesh.WithCodec(codec.BuildCustomCodec(&codec_text.Encoder{}, &codec_text.Decoder{})),
				)
				meshClient := client.DefaultClient
				var respBody []byte
				if _, err = meshClient.SyncCall(context.Background(), request, &respBody); err != nil {
					log.Errorsf("publish metrics to management agent failed, error=%++v", err)

				}
			}
		}
	}()

	return nil
}
